home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / kms20src.lha / KMSS / rexx.c < prev    next >
C/C++ Source or Header  |  1994-07-03  |  13KB  |  450 lines

  1. /**********************************
  2.  *              KMS               *
  3.  **********************************
  4.  *  ©1993 by BlackMagic Software  *
  5.  **********************************
  6.  *                                *
  7.  **********************************/
  8.  
  9. #include <KMS/KMS.h>
  10. #include <KMS/KMS_devlib.h>
  11. #include <KMS/KMS_rexx.h>
  12.  
  13. Prototype ULONG upRexxPort(STRPTR, struct rexxCommandList *, STRPTR, VOID (*)());
  14. Prototype VOID dnRexxPort(VOID);
  15. Prototype VOID dispRexxPort(VOID);
  16. Prototype struct RexxMsg *sendRexxCmd(STRPTR, APTR, STRPTR, STRPTR, STRPTR, STRPTR);
  17. Prototype VOID replyRexxCmd(struct RexxMsg *, ULONG, STRPTR);
  18. Prototype BOOL SetARexxLastError(struct RexxMsg *, STRPTR);
  19. Prototype UBYTE OpenRexxLib(VOID);
  20. Prototype VOID CloseRexxLib(VOID);
  21.  
  22. /******* Alles folgende auf Grundlage von... *******/
  23.  
  24. static STRPTR blurb = "Radical Eye MinRexx 0.4";
  25.  
  26. /***************************************************/
  27.  
  28. // Local Prototypes
  29.  
  30. static UWORD CmdCmp(STRPTR, STRPTR);
  31. static VOID (*UserDisp)(struct RexxMsg *, struct rexxCommandList *, STRPTR);
  32. static VOID ReplyToIt(register struct RexxMsg *);
  33.  
  34. // Variables
  35.  
  36. struct MsgPort *MyRexxPort = NULL;        /* this is *our* rexx port */
  37. int BringerDown = 0;                      /* are we trying to shut down? */
  38. struct rexxCommandList *GlobalRCL = NULL; /* our command association list */
  39. ULONG StillNeedReplies = 0;               /* how many replies are pending? */
  40. ULONG RexxPortBit = 0;                    /* what bit to wait on for Rexx? */
  41. STRPTR Extension = NULL;                  /* the Extension for macros */
  42. struct RexxMsg *ORexxMsg = NULL;          /* the outstanding Rexx message */
  43. struct RexxMsg *MeetMessage = NULL;       /* Auf diese wird gewartet */
  44.  
  45. static TEXT dbtext[160]; /* Für Debugging-Zwecke */
  46.  
  47. // Our library base.  Don't you dare close this!
  48.  
  49. struct RxsLib *RexxSysBase;
  50.  
  51. /*
  52.  *   upRexxPort() returns the signal bit to wait on for Rexx messages.
  53.  *   If something goes wrong, it simply returns a `0'.  Note that this
  54.  *   function is safe to call multiple times because we check to make
  55.  *   sure we haven't opened already.  It's also a quick way to change
  56.  *   the association list or dispatch function.
  57.  */
  58.  
  59. ULONG upRexxPort(STRPTR s, struct rexxCommandList *rcl, STRPTR exten, VOID (*uf)())
  60.    {
  61.    if (rcl == NULL || uf == NULL)
  62.       return 0;
  63.  
  64.    BringerDown = 0;
  65.  
  66.    if(MyRexxPort == NULL)
  67.       {
  68.       Forbid();
  69.       if (FindPort(s) == NULL)
  70.          MyRexxPort = CreatePort(s, 0);
  71.       Permit();
  72.       if (MyRexxPort != NULL)
  73.          RexxPortBit = (1L << MyRexxPort->mp_SigBit);
  74.       }
  75.  
  76.    GlobalRCL = rcl;
  77.    Extension = exten;
  78.    UserDisp = uf;
  79.    return RexxPortBit;
  80.    }
  81.  
  82. /*
  83.  *   This function closes the rexx library, but only if it is open
  84.  *   and we aren't expecting further replies from REXX.  It's
  85.  *   *private*, but it doesn't have to be; it's pretty safe to
  86.  *   call anytime.
  87.  */
  88.  
  89. VOID CloseRexxLib(VOID)
  90.    {
  91.    if(StillNeedReplies == 0 && RexxSysBase)
  92.       {
  93.       CloseLibrary((struct Library *)RexxSysBase);
  94.       RexxSysBase = NULL;
  95.       }
  96.    }
  97.  
  98. /*
  99.  *   This function closes down the Rexx port.  It is always safe to
  100.  *   call, and should *definitely* be made a part of your cleanup
  101.  *   routine.  No arguments and no return.  It removes the Rexx port,
  102.  *   replies to all of the messages and insures that we get replies
  103.  *   to all the ones we sent out, closes the Rexx library, deletes the
  104.  *   port, clears a few flags, and leaves.
  105.  */
  106.  
  107. VOID dnRexxPort(VOID)
  108.    {
  109.    if(MyRexxPort)
  110.       {
  111.       RemPort(MyRexxPort);
  112.       BringerDown = 1;
  113.  
  114.       /*
  115.        *   A message still hanging around?  We kill it off.
  116.        */
  117.  
  118.       if(ORexxMsg)
  119.          {
  120.          ORexxMsg->rm_Result1 = RXERRORIMGONE;
  121.          ReplyMsg((struct Message *)ORexxMsg);
  122.          ORexxMsg = NULL;
  123.          }
  124.  
  125.       dispRexxPort();
  126.  
  127.       while(StillNeedReplies)
  128.          {
  129.          WaitPort(MyRexxPort);
  130.          dispRexxPort();
  131.          }
  132.  
  133.       CloseRexxLib();
  134.       DeletePort(MyRexxPort);
  135.       MyRexxPort = NULL;
  136.       }
  137.  
  138.    RexxPortBit = 0;
  139.    }
  140.  
  141. /*
  142.  *   Here we dispatch any REXX messages that might be outstanding.
  143.  *   This is the main routine for handling Rexx messages.
  144.  *   This function is fast if no messages are outstanding, so it's
  145.  *   pretty safe to call fairly often.
  146.  *
  147.  *   If we are bring the system down and flushing messages, we reply
  148.  *   with a pretty serious return code RXERRORIMGONE.
  149.  *
  150.  *   No arguments, no returns.
  151.  */
  152.  
  153. VOID dispRexxPort(VOID)
  154.    {
  155.    register struct RexxMsg *rexxmsg;
  156.    register struct rexxCommandList *rcl;
  157.    register STRPTR p;
  158.    register UBYTE dontreply;
  159.  
  160.    /*
  161.     *   If there's no rexx port, we're out of here.
  162.     */
  163.  
  164.    if(MyRexxPort == NULL)
  165.       return;
  166.  
  167.    /*
  168.     *   Otherwise we have our normal loop on messages.
  169.     */
  170.  
  171.    while(rexxmsg = (struct RexxMsg *)GetMsg(MyRexxPort))
  172.       {
  173.       /*
  174.        *   If we have a reply to a message we sent, we look at the second
  175.        *   argument.  If it's set, it's a function we are supposed to call
  176.        *   so we call it.  Then, we kill the argstring and the message
  177.        *   itself, decrement the outstanding count, and attempt to close
  178.        *   down the Rexx library.  Note that this call only succeeds if
  179.        *   there are no outstanding messages.  Also, it's pretty quick, so
  180.        *   don't talk to me about efficiency.
  181.        */
  182.  
  183.       if(rexxmsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
  184.          {
  185.          VOID (*replytoit)(register struct RexxMsg *);
  186.  
  187.          /*
  188.          sprintf(dbtext, "Reply received: Result1= %8lx Result2= %8lx\n", rexxmsg->rm_Result1, rexxmsg->rm_Result2);
  189.          Out(dbtext);
  190.          */
  191.  
  192.          if(rexxmsg->rm_Args[1])
  193.             {
  194.             replytoit = rexxmsg->rm_Args[1];
  195.             replytoit(rexxmsg);
  196.             }
  197.  
  198.          DeleteArgstring(rexxmsg->rm_Args[0]);
  199.          DeleteRexxMsg(rexxmsg);
  200.          StillNeedReplies--;
  201.          CloseRexxLib();
  202.          }
  203.       else
  204.          {
  205.          /*
  206.           *   The default case is we got a message and we need to check it for
  207.           *   primitives.  We skip past any initial tabs or spaces and initialize
  208.           *   the return code fields.
  209.           */
  210.  
  211.          p = (STRPTR)rexxmsg->rm_Args[0];
  212.          while (*p && *p <= ' ')
  213.             p++;
  214.  
  215.          /*
  216.          if(rexxmsg->rm_Args[2])
  217.             sprintf(dbtext, "Commd from %02d : [%s]\n", rexxmsg->rm_Args[2], p);
  218.          else
  219.             sprintf(dbtext, "Commd from ?? : [%s]\n", p);
  220.          Out(dbtext);
  221.          */
  222.  
  223.          rexxmsg->rm_Result1 = 0;
  224.          rexxmsg->rm_Result2 = 0;
  225.  
  226.          /*
  227.           *   If somehow the reply is already done or postponed, `dontreply' is
  228.           *   set.
  229.           */
  230.  
  231.          dontreply = 0;
  232.  
  233.          /*
  234.           *   If the sky is falling, we just blow up and replymsg.
  235.           */
  236.  
  237.          if(BringerDown)
  238.             rexxmsg->rm_Result1 = RXERRORIMGONE;
  239.          else
  240.             {
  241.             /*
  242.              *   Otherwise we search down our association list, comparing commands,
  243.              *   until we get a match.  If we get a match, we call the dispatch
  244.              *   function with the appropriate arguments, and break out.
  245.              */
  246.  
  247.             ORexxMsg = rexxmsg;
  248.             for(rcl = GlobalRCL; rcl->name; rcl++)
  249.                {
  250.                if(CmdCmp(rcl->name, p) == 0)
  251.                   {
  252.                   UserDisp(rexxmsg, rcl, p+strlen(rcl->name));
  253.                   break;
  254.                   }
  255.                }
  256.  
  257.             /*
  258.              *   If we broke out, rcl will point to the command we executed; if we
  259.              *   are at the end of the list, we didn't understand the command.  In
  260.              *   this case, if we were supplied an extension in upRexxPort, we know
  261.              *   that we should send the command out, so we do so, asynchronously.
  262.              *   The asynchronous send takes care of our reply.  If we were given a
  263.              *   NULL extension, we bitch that the command didn't make sense to us.
  264.              */
  265.  
  266.             if(rcl->name == NULL)
  267.                {
  268.                if(Extension)
  269.                   {
  270.                   sendRexxCmd(rexxmsg->rm_Args[0], (APTR)&ReplyToIt, (STRPTR)rexxmsg, NULL, NULL, NULL);
  271.                   dontreply = 1;
  272.                   }
  273.                else
  274.                   rexxmsg->rm_Result1 = RXERRORNOCMD;
  275.                }
  276.             }
  277.  
  278.          /*
  279.           *   Finally, reply if appropriate.
  280.           */
  281.  
  282.          ORexxMsg = NULL;
  283.          if(!dontreply)
  284.             ReplyMsg((struct Message *)rexxmsg);
  285.          }
  286.       }
  287.    }
  288.  
  289. /*
  290.  *   This is the function we use to see if the command matches
  291.  *   the command string.  Not case sensitive.
  292.  *   Make sure all commands in the rexxCommandList are given in lower case!
  293.  */
  294.  
  295. static UWORD CmdCmp(register STRPTR c, register STRPTR m)
  296.    {
  297.    while(*c && ((*c == *m) || (*c == *m + 32 && ('a' <= *c && *c <= 'z'))))
  298.       {
  299.       c++;
  300.       m++;
  301.       }
  302.  
  303.    if(*m != ' ' && *m != '\0')
  304.       return 1;
  305.  
  306.    return *c;
  307.    }
  308.  
  309. /*
  310.  *   Opens the Rexx library if unopened.  Returns success (1) or
  311.  *   failure (0).  This is another function that is *private* but
  312.  *   that doesn't have to be.
  313.  */
  314.  
  315. UBYTE OpenRexxLib(VOID)
  316.    {
  317.    if(RexxSysBase)
  318.       return 1;
  319.  
  320.    return (UBYTE)((RexxSysBase = (struct RxsLib *)OpenLibrary(RXSNAME, 0L)) != NULL);
  321.    }
  322.  
  323. /*
  324.  *   This is the general ARexx command interface, but is not the one
  325.  *   you will use most of the time; ones defined later are easier to
  326.  *   understand and use.  But they all go through here.
  327.  */
  328.  
  329. struct RexxMsg *sendRexxCmd(STRPTR s, APTR f, STRPTR p1, STRPTR p2, STRPTR p3, STRPTR port)
  330.    {
  331.    register struct MsgPort *rexxport;
  332.    register struct RexxMsg *rexxmsg;
  333.  
  334.    /*
  335.    sprintf(dbtext, "Sending Command: [%s] to [%s]\n", s, port);
  336.    Out(dbtext);
  337.    */
  338.  
  339.    if (MyRexxPort == NULL || StillNeedReplies > MAXRXOUTSTANDING-1)
  340.       return NULL;
  341.  
  342.    rexxmsg = NULL;
  343.  
  344.    if(OpenRexxLib()
  345.       && (rexxmsg = CreateRexxMsg(MyRexxPort, Extension, MyRexxPort->mp_Node.ln_Name))
  346.       && (rexxmsg->rm_Args[0] = CreateArgstring(s, (ULONG)strlen(s))))
  347.       {
  348.       rexxmsg->rm_Action = RXCOMM;
  349.       rexxmsg->rm_Args[1] = (STRPTR)f;
  350.       rexxmsg->rm_Args[2] = NULL; /* Sending KMS-Port */
  351.       rexxmsg->rm_Args[3] = p1;
  352.       rexxmsg->rm_Args[4] = p2;
  353.       rexxmsg->rm_Args[5] = p3;
  354.       if(port)
  355.          rexxmsg->rm_Node.mn_Node.ln_Name = port;
  356.       else
  357.          rexxmsg->rm_Node.mn_Node.ln_Name = RXSDIR;
  358.  
  359.       Forbid();
  360.       if(port)
  361.          rexxport = FindPort(port);
  362.       else
  363.          rexxport = FindPort(RXSDIR);
  364.       if(rexxport)
  365.          PutMsg(rexxport, (struct Message *)rexxmsg);
  366.       Permit();
  367.  
  368.       if(rexxport)
  369.          {
  370.          StillNeedReplies++;
  371.          return rexxmsg;
  372.          }
  373.       else
  374.          DeleteArgstring(rexxmsg->rm_Args[0]);
  375.       }
  376.  
  377.    if(rexxmsg)
  378.       DeleteRexxMsg(rexxmsg);
  379.  
  380.    CloseRexxLib();
  381.  
  382.    return NULL;
  383.    }
  384.  
  385. /*
  386.  *   This function sets things up to reply to the message that caused
  387.  *   it when we get a reply to the message we are sending out here.
  388.  *   But first the function we pass in, which actually handles the reply.
  389.  *   Note how we get the message from the Args[3]; Args[0] is the command,
  390.  *   Args[1] is this function, and Args[3]..Args[5] are any parameters
  391.  *   passed to sendRexxCmd() as p1..p3.  We pass the result codes right
  392.  *   along.
  393.  */
  394.  
  395. static VOID ReplyToIt(register struct RexxMsg *msg)
  396.    {
  397.    register struct RexxMsg *omsg;
  398.  
  399.    omsg = (struct RexxMsg *)(msg->rm_Args[3]);
  400.    replyRexxCmd(omsg, msg->rm_Result1, NULL);
  401.    ReplyMsg((struct Message *)omsg);
  402.    }
  403.  
  404. /*
  405.  *   This function passes back an errorcode or a return string.
  406.  */
  407.  
  408. VOID replyRexxCmd(struct RexxMsg *msg, ULONG errorcode, STRPTR string)
  409.    {
  410.    ULONG secondary = 0;
  411.  
  412.    if(errorcode == 0 && (msg->rm_Action & RXFF_RESULT))
  413.       {
  414.       if(string && OpenRexxLib())
  415.          secondary = (ULONG)CreateArgstring(string, (ULONG)strlen(string));
  416.       else
  417.          secondary = 0;
  418.       }
  419.    else if(errorcode == 0 && string)
  420.       secondary = (ULONG)string;
  421.  
  422.    msg->rm_Result1 = errorcode;
  423.    msg->rm_Result2 = secondary;
  424.  
  425.    CloseRexxLib();
  426.    }
  427.  
  428. /*
  429.  * This function will set an error string for the ARexx
  430.  * application in the variable defined as <appname>.LASTERROR
  431.  *
  432.  * Note that this can only happen if there is an ARexx message...
  433.  *
  434.  * This returns TRUE if it worked, FALSE if it did not...
  435.  */
  436.  
  437. BOOL SetARexxLastError(struct RexxMsg *rmsg, STRPTR errorstring)
  438.    {
  439.    STRPTR errorname = "KMS.LASTERROR";
  440.  
  441.    if(rmsg)
  442.       {
  443.       if(!SetRexxVar((struct Message *)rmsg, errorname, errorstring, (ULONG)strlen(errorstring)))
  444.          return TRUE;
  445.       }
  446.  
  447.    return FALSE;
  448.    }
  449.  
  450.